package saves;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import game.Configurations;
import game.TextManager;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class SaveManager {

    private HashMap<String, Profile> profiles;
    private String profileAtual;
    private int saveAtual;
    
    public static String SAVE_PATH = "saves\\";

    public static class Profile {

        private String nome;
        private HashMap<Integer, Save> saves;
        private int lastSave;

        public Profile(String nome) {
            this.nome = nome;
            this.saves = new HashMap<>();
            this.lastSave = loadLastSave();
        }
        
        public Set<Map.Entry<Integer, Save>> getSet() {
            return this.saves.entrySet();
        }

        public void put(int cod, Save save) {
            lastSave = cod;
            setLastSave();
            saves.put(cod, save);
        }

        public boolean tem(int cod) {
            return saves.containsKey(cod) && saves.get(cod) != null;
        }
        
        public int getQtosSaves() {
            return this.saves.size();
        }

        public Save get(int cod) {
            lastSave = cod;
            setLastSave();
            return saves.get(cod);
        }

        public int getLastSave() {
            return this.lastSave;
        }
        
        public Save getSave() {
            return get(getLastSave());
        }
        
        public int getNextSave() {
            File[] fs = new File(SAVE_PATH + nome + "\\saves").listFiles();
            if (fs.length == 0)
                return 0;
            
            try {
                return Integer.parseInt(fs[fs.length - 1].getName()) + 1;
            } catch (Exception e) {
                return saves.size() + 1;
            }
        }

        private int loadLastSave() {
            int a;
            try (BufferedReader r = new BufferedReader(new FileReader(SAVE_PATH + nome + "\\config.dat"))) {
                a = Integer.parseInt(r.readLine());
            } catch (IOException | NumberFormatException e) {
                a = 0;
            }
            return a;
        }

        private void setLastSave() {
            try (BufferedWriter p = new BufferedWriter(new FileWriter(SAVE_PATH + nome + "\\config.dat"))) {
                p.write(String.valueOf(lastSave));
            } catch (IOException e) {
            }
        }
    }
    
    public Save getSave() {
        return this.profiles.get(profileAtual).get(saveAtual);
    }
    
    public Profile getProfile() {
        return this.profiles.get(profileAtual);
    }
    
    public SaveManager() {
        profileAtual = null;
        saveAtual = -1;
        profiles = new HashMap<>();
        File[] folders = new File(SAVE_PATH).listFiles();
        if (folders != null)
            for (int i = 0; i < folders.length; i++) {
                String nome = folders[i].getName();
                profiles.put(nome, new Profile(nome));
            }
    }

    public void salvar() throws IOException {
        if (profileAtual != null && saveAtual != -1) {
            new File(SAVE_PATH + profileAtual + "\\saves\\" + saveAtual).mkdirs();
            try (Output output = new Output(new FileOutputStream(SAVE_PATH + profileAtual + "\\saves\\" + saveAtual + "\\save.dat"))) {
                new Kryo().writeObject(output, profiles.get(profileAtual).get(saveAtual));
            }
            profiles.get(profileAtual).lastSave = saveAtual;
            profiles.get(profileAtual).setLastSave();
        }
    }
    
    public void salvarNovo() throws IOException {
        salvar(profiles.get(profileAtual).getNextSave());
    }
    
    public void salvar(int pos) throws IOException {
        profiles.get(profileAtual).put(pos, (new Kryo()).copy(profiles.get(profileAtual).get(saveAtual)));
        saveAtual = pos;
        salvar();
        carregarSave(profileAtual, saveAtual);
    }

    public void adicionarSave(String nome, int nave) {
        profileAtual = nome;
        saveAtual = 0;

        profiles.put(profileAtual, new Profile(nome));
        profiles.get(profileAtual).put(saveAtual, new Save(nome, nave));
        new File(SAVE_PATH + profileAtual + "\\saves\\" + saveAtual).mkdirs();
        try {
            salvar();
        } catch (IOException e) {
            System.err.println("Houve um erro ao salvar o arquivo. Erro: " + e.getMessage());
        }
    }

    public int qtosSaves() {
        return profiles.size();
    }

    public String[] listaSaves() {
        String[] listaStrings = new String[profiles.size() + 1];
        listaStrings[0] = TextManager.t().NEW_GAME[3];
        Iterator<Map.Entry<String, Profile>> it = profiles.entrySet().iterator();
        int i = 0;
        while (it.hasNext())
            listaStrings[++i] = it.next().getKey();
        return listaStrings;
    }
    
    public int selectedSave() {
        return selectedSave(listaSaves());
    }
    
    public int selectedSave(String[] saves) {
        for (int i = 0; i < saves.length; i++)
            if (saves[i].equals(Configurations.LAST_PROFILE))
                return i;
        return -1;
    }
    
    public String getProfileAtual() {
        return this.profileAtual;
    }

    public void carregarSave(String nome) throws IOException {
        carregarSave(nome, profiles.get(nome).getLastSave());
    }

    public void carregarSave(String nome, int save) throws IOException {
        this.profileAtual = nome;
        Configurations.LAST_PROFILE = nome;
        this.saveAtual = save;
        
        try (Input input = new Input(new FileInputStream(SAVE_PATH + nome + "\\saves\\" + save + "\\save.dat"))) {
            Save s = new Kryo().readObject(input, Save.class);
            profiles.get(nome).put(save, s);
        }
        
        //Adicionar todos os outros save do profile à lista
        File[] fs = new File(SAVE_PATH + nome + "\\saves").listFiles();
        for (int i = 0; i < fs.length; i++) {
            int cod = Integer.parseInt(fs[i].getName());
            if (!profiles.get(nome).tem(cod))
                profiles.get(nome).put(cod, null);
        }
        
        if (profiles.get(nome).get(save).hasToLoad())
            profiles.get(nome).get(save).carregarGalaxia();
        
        profiles.get(profileAtual).lastSave = saveAtual;
        profiles.get(profileAtual).setLastSave();
    }

    public void atualizar(int deltaT) {
        profiles.get(profileAtual).get(saveAtual).atualizar(deltaT);
    }

    public void desenhar() {
        profiles.get(profileAtual).get(saveAtual).desenhar();
    }

    public EntidadeNave getPlayer() {
        return profiles.get(profileAtual).get(saveAtual).getPlayer();
    }
    
    public Area getCurrentArea() {
        return profiles.get(profileAtual).get(saveAtual).getCurrentArea();
    }
}